#Copyright (c) 2025, Alibaba Cloud and its affiliates;
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.



import json

from dataclasses import field
from flask import jsonify, make_response, request
from webargs.flaskparser import parser

from common_libs.operate_logging import logging_opt

FCEEXCEPTIONS = {
    'e':[
        {
            'name': 'InvalidParameters',
            'error_code': 'InvalidParameters',
            'http_code': 409,
            'message': '%s is Invalid'
        },
        {
            'name': 'InvalidParameters.Empty',
            'error_code': 'InvalidParameters.Empty',
            'http_code': 410,
            'message': '%s is required parameters. Cannot be empty'
        },
        {
            'name': 'InvalidParameters.Error',
            'error_code': 'InvalidParameters.Error',
            'http_code': 410,
            'message': 'The %s is not conform to the format.'
        },
        {
            'name': 'InvalidParameters.AlreadyExists',
            'error_code': 'InvalidParameters.AlreadyExists',
            'http_code': 410,
            'message': 'Parameter: %s, value: %s already exists'
        },
        {
            'name': 'InvalidParameters.ParseError',
            'error_code': 'InvalidParameters.ParseError',
            'http_code': 410,
            'message': 'Parameter parse error: %s'
        },
        {
            'name': 'OperationFailed.FceutilCommand',
            'error_code': 'OperationFailed.FceutilCommand',
            'http_code': 413,
            'message': 'cmd:%s Operation failed because:%s'
        },
        {
            'name': 'Timeout.FceutilCommand',
            'error_code': 'Timeout.FceutilCommand',
            'http_code': 412,
            'message': 'cmd:%s timeout'
        },
        {
            'name': 'InvalidDataType.FceutilResult',
            'error_code': 'InvalidDataType.FceutilResult',
            'http_code': 413,
            'message': 'The fceutil return DataType error: %s'
        },
        {
            'name': 'OperationFailed.SystemCommand',
            'error_code': 'OperationFailed.SystemCommand',
            'http_code': 413,
            'message': 'cmd:%s Operation Failed'
        },
        {
            'name': 'OperationFailed.Database',
            'error_code': 'OperationFailed.Database',
            'http_code': 413,
            'message': 'because %s'
        },
        {
            'name': 'InvalidToken.Unauthorized',
            'error_code': 'InvalidToken.Unauthorized',
            'http_code': 413,
            'message': 'Token authentication failed'
        },
        {
            'name': 'ErrorOpenApi',
            'error_code': 'ErrorOpenApi',
            'http_code': 413,
            'message': 'call OpenApi msg:%s'
        },
        {
            'name': 'Deploy.ToolNotFound',
            'error_code': 'Deploy.ToolNotFound',
            'http_code': 415,
            'message': 'Kubernetes tool not found'
        },
        {
            'name': 'Deploy.OperatorNotFound',
            'error_code': 'Deploy.OperatorNotFound',
            'http_code': 415,
            'message': 'Kubray operator dir not found'
        },
        {
            'name': 'Deploy.ToolCheckFailed',
            'error_code': 'Deploy.ToolCheckFailed',
            'http_code': 415,
            'message': 'Kubernetes tools check failed'
        },
        {
            'name': 'Deploy.ToolInstallFailed',
            'error_code': 'Deploy.ToolInstallFailed',
            'http_code': 415,
            'message': 'Kubernetes tool install failed. Msg:%s'
        },
        {
            'name': 'Deploy.KubeNotFound',
            'error_code': 'Deploy.KubeNotFound',
            'http_code': 415,
            'message': 'Kubernetes cluster not found'
        },
        {
            'name': 'Deploy.OperatorCheckFailed',
            'error_code': 'Deploy.OperatorCheckFailed',
            'http_code': 416,
            'message': 'KubeRay Operator Check Failed'
        },
        {
            'name': 'Deploy.OperatorInstallFailed',
            'error_code': 'Deploy.OperatorInstallFailed',
            'http_code': 416,
            'message': 'KubeRay Operator Create Failed, err: %s'
        },
        {
            'name': 'Deploy.OperatorUnInstallFailed',
            'error_code': 'Deploy.OperatorUnInstallFailed',
            'http_code': 416,
            'message': 'KubeRay Operator Delete Failed'
        },
        {
            'name': 'RayCluster.NameAlreadyExists',
            'error_code': 'RayCluster.NameAlreadyExists',
            'http_code': 416,
            'message': 'Ray Cluster Name Already Exists'
        },
        {
            'name': 'RayCluster.ResourcesDeployFailed',
            'error_code': 'RayCluster.ResourcesDeployFailed',
            'http_code': 416,
            'message': 'Ray Cluster Dependency resources Deploy Failed'
        },
        {
            'name': 'RayCluster.ClusterInstallFailed',
            'error_code': 'RayCluster.ClusterInstallFailed',
            'http_code': 416,
            'message': 'Ray Cluster Install Failed'
        },
        {
            'name': 'RayCluster.ClusterNotExist',
            'error_code': 'RayCluster.ClusterNotExist',
            'http_code': 418,
            'message': 'Ray Cluster Do Not Exist. Msg: %s'
        },
        {
            'name': 'RayCluster.CleanResourcesFailed',
            'error_code': 'RayCluster.CleanResourcesFailed',
            'http_code': 418,
            'message': 'Ray Cluster Dependency resources clean Failed'
        },
        {
            'name': 'RayCluster.DeleteClusterFailed',
            'error_code': 'RayCluster.DeleteClusterFailed',
            'http_code': 418,
            'message': 'Ray Cluster Resources Delete Failed'
        },
    ]
}

class FceExceptionBase(Exception):
    def __init__(self, http_code, error_code, message):
        Exception.__init__(self)
        self.message = message
        self.error_code = error_code
        self.http_code = http_code

def logging_exception(app, error):
    if request.method == 'GET':
        request_id = request.args.get('RequestId', '')
        request_form_data = request.args
    else:
        request_id = request.form.get('RequestId', '') if request.form.get('RequestId', '') else request.json.get('RequestId', '')
        request_form_data = request.form

    data = {
        "Message": error.message,
        "RequestId": request_id
    }
    logging_opt('error', error.message)
    app.logger.error('Exception:%s data:%s request:%s ' % (error.error_code, data, json.dumps(request_form_data)))
    return data

def init_exception(app):
    @app.errorhandler(FceExceptionBase)
    def exception_response(error):
        # logging
        data = logging_exception(app, error)

        #response
        error_message = {"result": 'Failed', "message": {"code": error.error_code, "data": data}}
        response = make_response(jsonify(error_message))
        #response.status_code = error.error_code
        #response.status = str(error.http_code) + ' ' + error.error_code
        return response
    
    @parser.error_handler
    def exception_parser_response(error, req, schema, *, error_status_code, error_headers):
        if request.method == 'GET':
            msg = error.messages['args']
        else:
            msg = error.messages['form']
        miss_feild = ''
        for key in msg:
            miss_feild = miss_feild + key

        FceException('InvalidParameters.Empty', miss_feild)

    @app.errorhandler(500)
    def internal_server_error(e):
        FceException('InvalidParameters.Empty')
      
    @app.errorhandler(422)
    def handle_422_error(e):
        FceException('InvalidParameters') 

def get_exception(name):
    ex = {
            'name': 'UnknownError',
            'error_code': 'UnknownError',
            'http_code': 513,
            'message': '%s'
    }
    for e in FCEEXCEPTIONS.get('e'):
        if e['name'] == name:
            return e

    return ex

def FceException(ex, *msgs):
    e = get_exception(ex)
    msg = e['message']
    if msgs:
       msg = e['message'] % msgs
    raise FceExceptionBase(e['http_code'], e['error_code'], msg)